/*
 * Copyright (c) 2007, Nubo Technologies
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *    * Neither the name of the Nubo Technologies nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.nubotech.gwt.oss.browser.client.ui;

import com.extjs.gxt.ui.client.Style;
import com.extjs.gxt.ui.client.Style.SelectionMode;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.WindowEvent;
import com.extjs.gxt.ui.client.event.TableEvent;
import com.extjs.gxt.ui.client.event.TableListener;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.table.CellRenderer;
import com.extjs.gxt.ui.client.widget.table.DateTimeCellRenderer;
import com.extjs.gxt.ui.client.widget.table.Table;
import com.extjs.gxt.ui.client.widget.table.TableColumn;
import com.extjs.gxt.ui.client.widget.table.TableColumnModel;
import com.extjs.gxt.ui.client.widget.table.TableItem;
import com.extjs.gxt.ui.client.widget.table.TableView;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.URL;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.nubotech.gwt.oss.browser.client.Main;
import com.nubotech.gwt.oss.client.Bucket;
import com.nubotech.gwt.oss.client.BucketResult;
import com.nubotech.gwt.oss.client.BucketResultCallback;
import com.nubotech.gwt.oss.client.ObjectHolder;
import com.nubotech.gwt.oss.client.ObjectHolderResult;
import com.nubotech.gwt.oss.client.ObjectHolderResultCallback;
import com.nubotech.gwt.oss.client.OnlineStorageService;
import com.nubotech.gwt.oss.client.OnlineStorageServiceFactory;
import com.nubotech.gwt.oss.client.auth.AuthenticationManager;
import com.nubotech.gwt.oss.client.auth.Credential;
import com.nubotech.gwt.oss.client.util.LogUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author jonnakkerud
 */
public class FileView extends Composite {
    private VerticalPanel main;
    
    private PathBar pathBar;
    
    private Table table;
    
    public FileView(PathBar pathBar) {
        this.pathBar = pathBar;
        initWidget(main = new VerticalPanel());
        initGui();
        
        pathBar.addChangeListener(new ChangeListener() {
            public void onChange(Widget sender) {
                reload();
            }
        });
    }
            
    public void reload() {
        DeferredCommand.addCommand(new Command() {
            public void execute() {
                Map params = null;
                String prefix = pathBar.getPrefix();
                if (prefix != null && prefix.length() > 0) {
                    params = new HashMap();
                    params.put("prefix", prefix+BrowserView.DEFAULT_DELIMITER);
                    params.put("delimiter", BrowserView.DEFAULT_DELIMITER); // TODO configurable
                    params.put("marker", "");
                }

                load(pathBar.getBucket(), params);
            }
        });
    }
    
    private void load(String bucketName, Map params) {
        Credential c = AuthenticationManager.instance().getLogin();
        if (c != null) {
            OnlineStorageService oss = OnlineStorageServiceFactory.getService(c);
            if (bucketName == null) {
                oss.listAllBuckets(new BucketResultCallback() {
                    public void onBucketResult(BucketResult bucketResult) {
                        createDataTableModel(bucketResult);
                    }
                });
                
            } else {
                oss.listBucket(bucketName, params, new ObjectHolderResultCallback() {
                    public void onObjectHolderResult(ObjectHolderResult objectHolderResult) {
                        createDataTableModel(objectHolderResult);
                    }
                });
            }
        }
    }
    
    private void initGui() {
        // create the columns
        TableColumnModel cm = createColumnModel();
                
        table = new Table(cm);
        table.setView(new ThisTableView());
        
        table.setSelectionMode(SelectionMode.MULTI);  
        table.setHorizontalScroll(true);        
        table.addTableListener(new ThisTableListener());       
        
        ContentPanel panel = new ContentPanel();  
        panel.setHeaderVisible(false);
        panel.setLayout(new FitLayout());  
        panel.add(table);
        
        panel.setSize(375, 350);         
        
        main.add(panel);
        
        // TODO split pane for file details: data, metadata        
        
    }

    private TableColumnModel createColumnModel() {
        final DateTimeFormat dateFormat = DateTimeFormat.getShortDateTimeFormat();
        
        List<TableColumn> columns = new ArrayList<TableColumn>();
        
        TableColumn col = new TableColumn("File Name", 250);  
        col.setMinWidth(75);  
        col.setMaxWidth(300);
        col.setRenderer(new CellRenderer<TableItem>() {  
            public String render(TableItem item, String property, Object value) {  
                return formatFile((File)value);  
            }  
        });                  
        columns.add(col);
        
        col = new TableColumn("Size", 50);
        col.setRenderer(new CellRenderer<TableItem>() {  
            public String render(TableItem item, String property, Object value) {  
                Integer i = (Integer)value;
                return i.toString();
            }  
        });                  
        columns.add(col);
         
        col = new TableColumn("Date", 100);
        col.setRenderer(new DateTimeCellRenderer(dateFormat));
        columns.add(col);
        
        TableColumnModel cm = new TableColumnModel(columns);
        return cm;
    }
        
    private void createDataTableModel(BucketResult bucketResult) {
        removeAll();
        for (int i = 0; i < bucketResult.getRowCount(); i++) {
            Bucket b = bucketResult.get(i);
            File f = new File(b.getName(), null);
            f.lastModified = b.getCreationDate();
            addRow(f);
        }
    }

    private void createDataTableModel(ObjectHolderResult objectHolderResult) {
        removeAll();
        //String prefix = pathBar.getPrefix();
        //String filterPath = pathBar.getPrefix() != null ? pathBar.getPrefix() : pathBar.getBucket();
        String filterPath = pathBar.getPrefix();
        List model = new ArrayList();
        //int row = 0;
        for (int i = 0; i < objectHolderResult.getRowCount(); i++) {
            ObjectHolder o = objectHolderResult.get(i);
            String[] parts = PathBar.tokenizeKey(o.getKey(), filterPath);
            if (parts.length > 1) {
                // is a dir
                if (model.contains(parts[0]) == false) {
                    File f = new File(o.getBucket().getName(), o.getKey());
                    f.lastModified = o.getLastModified();
                    f.name = parts[0];
                    addRow(f);
                    model.add(parts[0]);
                }
            }
            else {
                // is a file/object
                File f = new File(o.getBucket().getName(), o.getKey());
                f.lastModified = o.getLastModified();
                f.size = o.getSize();
                f.name = parts[0];
                f.url = getUrl(o);
                addRow(f);
            }
        }        
    }
    
    private String getUrl(ObjectHolder o) {
        return (String) Main.get(o.getBucket().getName() + ":" + o.getKey());
    }
    
    public File[] getSelectedFiles() {
        ArrayList<File> ls = new ArrayList<File>();
        for (TableItem item : table.getSelectedItems()) {
            File f = (File) item.getValue(0);
            if (f.isDir() == false) {
                ls.add(f);
            }
        }
        return (File[]) ls.toArray(new File[ls.size()]);
    }
    
    
    // for debuging
    private void showParts(String[] parts) {
        StringBuffer sb = new StringBuffer();
        for (String s : parts) {
            sb.append(s).append(" | ");
        }
        GWT.log(sb.toString(), null);
    }
    
    private void addRow(File f) {
        TableItem item = new TableItem(new Object[] {f, new Integer(f.size), f.lastModified});
        table.add(item);        
    }
    
    public void removeAll() {
        // remove all items
        table.removeAll();
    }
    
    public void confirmDeleteSelected() {
        // show message box
        if (table.getSelectedItems() != null && table.getSelectedItems().size() > 0) {
            MessageBox.confirm("Confirm", "Are you sure you want to delete the selected items?", new Listener<WindowEvent>() {  
                public void handleEvent(WindowEvent we) {  
                    Button btn = we.buttonClicked;  
                    if ("Yes".equals(btn.getText())) {
                        deleteSelected();
                    }  
                }  
            });       
        }
    }
    
    public void deleteSelected() {
        for (TableItem item : table.getSelectedItems()) {
            delete(item);
        }
    }
    
    
    private String formatFile(File file) {
        String html = null;
        if (file.isDir()) {
            html = WidgetFactory.imageWithText(Main.images().folder(), file.getName());
        }
        else if (file.url != null) {
            html = WidgetFactory.createAnchor(file.getName(), file.url);
        }
        else {
            html = file.getName();
        }
        GWT.log("file.url: " + file.url, null);
        
        return html;
    }
    
    private void delete(TableItem item) {
        File fo = (File) item.getValue(0);
        Credential c = AuthenticationManager.instance().getLogin();
        if (c != null) {
            OnlineStorageService oss = OnlineStorageServiceFactory.getService(c);
            //String bucketName = pathBar.getBucket();
            if (fo.isBucket()) {
                oss.deleteBucket(fo.bucket);
                table.remove(item);
            } else {
                // TODO delete key as dir?
                // will recurse and delete all files in subdirs
                if (fo.isDir() == false) {
                    oss.deleteObject(fo.bucket, fo.key);
                    table.remove(item);
                }
            }
           
        }                
    }
    
    public class File {
        protected String bucket;
        protected String key;
        protected Date lastModified;
        protected int size;
        protected String name;
        protected String url;
        
        public File(String bucket, String key) {
            this.bucket = bucket;
            this.key = key;
        }
        
        
        public boolean isDir() {
            return (size == 0);
        }
        
        public boolean isBucket() {
            return (key == null);
        }
        
        public String getName() {
            if (name == null) {
                if (key == null) {
                    name = bucket;
                }
                else {
                    name = key;
                }
            }
            return name;
        }
    }        
    
    class ThisTableListener extends TableListener {
        public void tableRowDoubleClick(TableEvent te) {
            TableItem item = table.getItem(te.rowIndex);
            clickDown((File)item.getValue(0));
        }
    }
    
    private void clickDown(File f) {
        String path = pathBar.getPath();
        
        if (f.isBucket()) {
            path = f.bucket;
        }
        else if (f.isDir()) {
            path = path + f.getName();
        }
        else {
            // its a file object do nothing
        }
        
        
        // add current prefix
        // setPath (prefix) on PathBar
        pathBar.setPath(path);
    }
    
    class ThisTableView extends TableView {
        public int getCellIndex(Element target) {
            String index = target.getAttribute("index");
            if (index.length() == 0) {
                target = DOM.getParent(target);
                while (target != null) {
                    index = target.getAttribute("index");
                    if (index.length() == 0) {
                        target = DOM.getParent(target);
                    } else {
                        break;
                    }
                }
            }
            return index.length() == 0 ? Style.DEFAULT : Integer.parseInt(index);
        }
    }
    
    
}
